package com.ala4.oxcafe.service.impl;

import com.ala4.oxcafe.boot.manager.CustomUserDetails;
import com.ala4.oxcafe.boot.page.PageDomain;
import com.ala4.oxcafe.boot.utils.DetailsHelper;
import com.ala4.oxcafe.common.utils.collection.CollUtil;
import com.ala4.oxcafe.common.utils.object.ObjectUtil;
import com.ala4.oxcafe.dto.ResetPasswordDTO;
import com.ala4.oxcafe.dto.UserRoleRelDTO;
import com.ala4.oxcafe.entity.MenuInfo;
import com.ala4.oxcafe.entity.RoleInfo;
import com.ala4.oxcafe.entity.UserInfo;
import com.ala4.oxcafe.entity.UserRoleRel;
import com.ala4.oxcafe.exception.BusinessException;
import com.ala4.oxcafe.repository.MenuInfoRepository;
import com.ala4.oxcafe.repository.UserInfoRepository;
import com.ala4.oxcafe.repository.UserRoleRelRepository;
import com.ala4.oxcafe.service.UserInfoService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 用户信息服务类
 *
 * @author PING
 * @version 1.0.0
 * @date 2025/8/12 12:46
 */
@Service
@AllArgsConstructor
public class UserInfoServiceImpl implements UserInfoService {

    private final UserInfoRepository userInfoRepository;

    private final UserRoleRelRepository userRoleRelRepository;

    private final MenuInfoRepository menuInfoRepository;

    private final PasswordEncoder passwordEncoder;

    /**
     * 分页获取用户信息
     *
     * @param pageDomain 分页信息
     * @param userInfo   查询信息
     * @return
     */
    @Override
    public IPage<UserInfo> userInfoPage(PageDomain pageDomain, UserInfo userInfo) {
        IPage<UserInfo> userInfoIPage = userInfoRepository.selectUserInfoPage(pageDomain, userInfo);

        List<UserInfo> records = userInfoIPage.getRecords();
        Set<Long> userIds = records.stream().map(UserInfo::getId).collect(Collectors.toSet());
        if (CollUtil.isNotEmpty(userIds)) {
            Map<Long, List<RoleInfo>> roleInfoMap = userRoleRelRepository.selectUserRole(userIds);
            for (UserInfo record : records) {
                List<RoleInfo> roleInfos = roleInfoMap.get(record.getId());
                record.setRoleCodes(Optional.ofNullable(roleInfos).orElse(CollUtil.newArrayList()).stream().map(RoleInfo::getRoleCode).toList());
                record.setRoleIds(Optional.ofNullable(roleInfos).orElse(CollUtil.newArrayList()).stream().map(RoleInfo::getId).toList());
            }
        }

        return userInfoIPage;
    }

    /**
     * 创建用户
     *
     * @param userInfo 用户信息
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserInfo createUserInfo(UserInfo userInfo) {
        // 保存用户信息
        userInfo = userInfoRepository.createUserInfo(userInfo);

        // 保存用户权限
        userRoleRelRepository.createUserRoleRel(userInfo.getId(), userInfo.getRoleIds());

        return userInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserInfo updateUserInfo(UserInfo userInfo) {

        UserInfo dbUserInfo = userInfoRepository.getById(userInfo.getId());
        if (ObjectUtil.isNull(dbUserInfo)) {
            throw new BusinessException("用户不存在[{}]", userInfo.getNickName());
        }

        dbUserInfo.setDeptId(userInfo.getDeptId());
        dbUserInfo.setPhoneNumber(userInfo.getPhoneNumber());
        dbUserInfo.setAvatar(userInfo.getAvatar());
        dbUserInfo.setEmail(userInfo.getEmail());
        dbUserInfo.setNickName(userInfo.getNickName());
        dbUserInfo.setSex(userInfo.getSex());
        dbUserInfo.setStatus(userInfo.getStatus());
        // 更新用户信息
        userInfoRepository.updateById(dbUserInfo);

        // 分配用户权限
        if (CollUtil.isNotEmpty(userInfo.getRoleIds())) {
            this.allocation(new UserRoleRelDTO(userInfo.getId(), userInfo.getRoleIds()));
        }

        return dbUserInfo;
    }

    @Override
    public void resetPassword(ResetPasswordDTO resetPasswordDTO, boolean checkOldPassword) {
        UserInfo dbUserInfo = userInfoRepository.getById(resetPasswordDTO.getUserId());
        if (ObjectUtil.isNull(dbUserInfo)) {
            throw new BusinessException("用户不存在");
        }
        if (checkOldPassword) {
            if (!passwordEncoder.matches(resetPasswordDTO.getOldPassword(), dbUserInfo.getPassword())) {
                throw new BusinessException("旧密码不正确");
            }
        }
        dbUserInfo.setPassword(passwordEncoder.encode(resetPasswordDTO.getNewPassword()));

        userInfoRepository.updateById(dbUserInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void allocation(UserRoleRelDTO userRoleRelDTO) {

        UserInfo userInfo = userInfoRepository.getById(userRoleRelDTO.getUserId());
        if (ObjectUtil.isNull(userInfo)) {
            throw new BusinessException("找不到用户信息");
        }

        // 先删除所有的数据
        userRoleRelRepository.remove(Wrappers.<UserRoleRel>lambdaQuery()
                .eq(UserRoleRel::getUserId, userRoleRelDTO.getUserId()));

        // 新增用户关联的角色
        List<UserRoleRel> userRoleRelList = userRoleRelDTO.getRoleIds()
                .stream().map(item -> new UserRoleRel(userRoleRelDTO.getUserId(), item)).toList();
        userRoleRelRepository.saveBatch(userRoleRelList);
    }

    @Override
    public List<MenuInfo> userMenu() {
        CustomUserDetails userDetails = DetailsHelper.getUserDetails();
        return menuInfoRepository.userMenu(userDetails.getUserId());
    }

    @Override
    public UserInfo userInfo(Long userId) {
        UserInfo userInfo = userInfoRepository.getById(userId);
        List<RoleInfo> roleInfos = userRoleRelRepository.selectUserRole(userInfo.getId());
        userInfo.setRoleIds(roleInfos.stream().map(RoleInfo::getId).toList());
        return userInfo;
    }

    @Override
    public List<String> userMenuV2() {
        CustomUserDetails userDetails = DetailsHelper.getUserDetails();
        return menuInfoRepository.userMenuV2(userDetails.getUserId());
    }

}
